﻿using DeepEarth.Map.Core;
using System.Collections.Generic;
using System;
using System.Windows;
using System.Windows.Media;
using System.Collections.ObjectModel;
using DeepEarth.Core;
namespace DeepEarth.Toolkit.Geometry
{
    public class Polygon : PathBase, ISelfPositioning, IMultiLocation
    {
        public static readonly DependencyProperty OuterRingProperty =
            DependencyProperty.Register("OuterRing", typeof(ObservableCollection<Location>), typeof(Polygon), new PropertyMetadata(OnOuterRingChanged));

        public ObservableCollection<Location> OuterRing
        {
            get { return (ObservableCollection<Location>)GetValue(OuterRingProperty); }
            set { SetValue(OuterRingProperty, value); }
        }

        static void OnOuterRingChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            Polygon self = (Polygon)sender;

            if (!object.ReferenceEquals(args.NewValue, self.Locations))
            {
                self.Locations = (ObservableCollection<Location>)args.NewValue;
            }
        }

        protected override void LocationPropertyChanged()
        {
            this.OuterRing = this.Locations;
        }

        public static readonly DependencyProperty InnerRingsProperty =
            DependencyProperty.Register("InnerRings", typeof(ObservableCollection<ObservableCollection<Location>>), typeof(Polygon), new PropertyMetadata(InnerRingsChangedHandler));

        public ObservableCollection<ObservableCollection<Location>> InnerRings
        {
            get { return (ObservableCollection<ObservableCollection<Location>>)GetValue(InnerRingsProperty); }
            set { SetValue(InnerRingsProperty, value); }
        }

        public static void InnerRingsChangedHandler(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            Polygon self = sender as Polygon;

            if (args.OldValue != null)
            {
                ObservableCollection<ObservableCollection<Location>> oldInnerRings = args.OldValue as ObservableCollection<ObservableCollection<Location>>;
                oldInnerRings.CollectionChanged -= self.locations_CollectionChanged;

                foreach (ObservableCollection<Location> oldInnerRing in oldInnerRings)
                {
                    oldInnerRing.CollectionChanged -= self.locations_CollectionChanged;
                }
            }

            if (args.NewValue != null)
            {
                ObservableCollection<ObservableCollection<Location>> newInnerRings = args.NewValue as ObservableCollection<ObservableCollection<Location>>;
                newInnerRings.CollectionChanged += self.locations_CollectionChanged;

                foreach (ObservableCollection<Location> newInnerRing in newInnerRings)
                {
                    newInnerRing.CollectionChanged += self.locations_CollectionChanged;
                }

                self.locations_CollectionChanged(null, null);
            }
        }

        void locations_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            BoundingRectangle = new LocationRectangle(this.OuterRing);
            Refresh();
        }

        public Polygon()
            : base()
        {
            this.Fill = new SolidColorBrush(Colors.White);
            this.InnerRings = new ObservableCollection<ObservableCollection<Location>>();
        }


        protected override void Refresh()
        {
            PathGeometry pg = new PathGeometry();

            pg.Figures.Add(ShapeHelper.CreateSafeFigure(OuterRing, LocationToPoint, true, MaxBound));

            if (InnerRings != null)
            {
                foreach (ObservableCollection<Location> innerRing in InnerRings)
                {
                    pg.Figures.Add(ShapeHelper.CreateSafeFigure(innerRing, LocationToPoint, true, MaxBound));
                }
            }

            this.Data = pg;
        }

        private double? originalStrokeThickness = null;
        public override void ApplyScale(double scale, double appliedScaleTransform)
        {
            if (originalStrokeThickness == null)
            {
                originalStrokeThickness = this.StrokeThickness;
            }

            // If stroke thickness is too small, the line will disappear even if we're enlarging.
            // 0.15 obtained through trial and error - depends on Static Layer Default width.
            //this.StrokeThickness = Math.Max(originalStrokeThickness.Value * appliedScaleTransform, 0.15);
            this.StrokeThickness = originalStrokeThickness.Value * appliedScaleTransform;
        }

    }


}